package com.novunda.license.sm2;

import com.novunda.ecc.KeyPair;
import com.novunda.ecc.SM2;

import java.util.concurrent.Semaphore;

/**
 * @author linfeng
 * @since 2016/10/19.
 */
public enum Sm2LoadSigleton {

    INSTANCE;

    private final SM2 sm2;
    private final Semaphore semaphore;

    Sm2LoadSigleton() {
        semaphore = new Semaphore(1);
        sm2 = new SM2();
    }

    private SM2 getSm2() {
        return sm2;
    }

    /**
     * 生成SM2椭圆曲线密钥对
     *
     * @return 成功返回密钥对对象，失败返回null
     */
    public KeyPair gen_key_pair() {
        try {
            semaphore.acquire();
            return getSm2().gen_key_pair();
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 数字签名
     *
     * @param AID   用户ID（长度不超过256）
     * @param M     待签名的数据
     * @param pvkey 私钥
     * @return 签名成功返回签名数据，签名失败返回null
     */
    public byte[] signature(final String AID, final byte[] M, final byte... pvkey) {
        try {
            semaphore.acquire();
            return getSm2().signature(AID, M, pvkey);
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 签名验签
     *
     * @param AID   用户ID（长度不超过256）
     * @param M     待验签的数据
     * @param sig   签名数据
     * @param pukey 数据发送方的公钥
     * @return 验签成功返回true，失败返回false
     */
    public boolean verify(final String AID, final byte[] M, final byte[] sig, final byte... pukey) {
        try {
            semaphore.acquire();
            return getSm2().verify(AID, M, sig, pukey);
        } catch (InterruptedException e) {
            return false;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 加密
     *
     * @param M     待加密的数据
     * @param pukey 数据接收方公钥
     * @return 加密成功返回密文，失败返回null
     */
    public byte[] encrypt(final byte[] M, final byte... pukey) {
        try {
            semaphore.acquire();
            return getSm2().encrypt(M, pukey);
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 解密
     *
     * @param cipher 待解密的数据
     * @param pvkey  私钥
     * @return 加密成功返回原文，失败返回null
     */
    public byte[] decrypt(final byte[] cipher, final byte... pvkey) {
        try {
            semaphore.acquire();
            return getSm2().decrypt(cipher, pvkey);
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 生成通讯密钥对
     *
     * @param policy 策略值（策略公钥）
     * @return 成功返回密钥对对象，失败返回null
     */
    public KeyPair gen_communication_key_pair(final byte... policy) {
        try {
            semaphore.acquire();
            return getSm2().gen_communication_key_pair(policy);
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 对称加密
     *
     * @param key 密钥，可以为null（内部使用默认密钥）
     * @param M   明文
     * @return 成功返回密文，失败返回null
     */
    public byte[] special_encrypt(final String key, final byte... M) {
        try {
            semaphore.acquire();
            return getSm2().special_encrypt(key, M);
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 对称解密
     *
     * @param key    密钥，可以为null（内部使用默认密钥）
     * @param cipher 密文
     * @return 成功返回原文，失败返回null
     */
    public byte[] special_decrypt(final String key, final byte... cipher) {
        try {
            semaphore.acquire();
            return getSm2().special_decrypt(key, cipher);
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 杂凑算法A
     *
     * @param M M原文
     * @return 成功返回杂凑值32Bytes，失败返回null
     */
    public byte[] hashA(final byte... M) {
        try {
            semaphore.acquire();
            return getSm2().hashA(M);
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

    /**
     * 杂凑算法B
     *
     * @param M M原文
     * @return 成功返回杂凑值32Bytes，失败返回null
     */
    public byte[] hashB(final byte... M) {
        try {
            semaphore.acquire();
            return getSm2().hashB(M);
        } catch (InterruptedException e) {
            return null;
        } finally {
            semaphore.release();
        }
    }

}
